/********************************************************************************
  * @file    codeeditor.h
  * @author  Lun Li
  * @version V2.2.0
  * @date    2022.7.8
  * @brief   This file contains all the functions prototypes for the CodeEditor.
  ******************************************************************************/

#ifndef CODEEDITOR_H
#define CODEEDITOR_H

#include <QPlainTextEdit>
#include <QMenu>
#include <QCheckBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QStringListModel>
#include <QQueue>
#include "programconfig.h"
#include "verilogsyntaxhighlighter.h"
#include "nomarginlayout.h"
#include "source.h"

QT_BEGIN_NAMESPACE
class QPaintEvent;
class QResizeEvent;
class QSize;
class QWidget;
QT_END_NAMESPACE

class LineNumberArea;

/************
  * CodeEditor类，一个代码编辑器，用于给用户提供代码编辑与显示。
  * 每个CodeEditor都对应着一个源文件。
  * （该类采用了Qt的CodeEditor例子，并做了修改）
  ***********/
class CodeEditor : public QPlainTextEdit
{
    Q_OBJECT

public:
    // 构造函数.
    // config: 程序的配置文件.
    // file: 该编辑器对应的源文件.
    // menu: 用户点击右键时弹出的菜单.
    // parent: 父窗口.
    explicit CodeEditor(ProgramConfig *const config,
                        Source *file,
                        QMenu *menu,
                        QWidget *parent = nullptr);
    ~CodeEditor();

    // 行号区域的绘制函数
    void lineNumberAreaPaintEvent(QPaintEvent *event);

    // 计算行号区域的宽度
    int lineNumberAreaWidth();

    // 获取与该编辑器对应的文件
    Source *file() const;

signals:
    // 当编辑器的焦点改变时，发出该信号.
    // focus为true表示获得焦点，false表示失去焦点
    void focusChanged(bool focus);

protected:
    // 编辑器尺寸改变
    void resizeEvent(QResizeEvent *event) override;

    // 编辑器获得焦点
    void focusInEvent(QFocusEvent *event) override;

    // 编辑器失去焦点
    void focusOutEvent(QFocusEvent *event) override;

    // 用户点击右键
    void contextMenuEvent(QContextMenuEvent *event) override;

private slots:
    // 根据最大行号，更新行号区域的宽度
    // blockCount: 代码总行数
    void updateLineNumberAreaWidth(int blockCount);

    // 高亮当前行
    void highlightCurrentLine();

    // 当编辑器状态改变时，更新行号区域.
    // rect: 编辑器占据的矩形.
    // dy: 编辑器右侧的垂直滚动条滚动的距离
    void updateLineNumberArea(const QRect &rect,
                              int dy);

    // 当配置文件改变时，更新编辑器
    void updateEditorConfig();

private:
    // 行号区域
    QWidget *lineNumberArea;

    // 右键菜单
    QMenu *contextMenu;

    // 对应的源文件
    Source *m_file;

    // 程序配置文件
    ProgramConfig *const m_config;
};

/************
  * LineNumberArea类，用于给代码编辑器显示行号区域。
  ***********/
class LineNumberArea : public QWidget
{
public:
    LineNumberArea(CodeEditor *editor) : QWidget(editor), codeEditor(editor)
    {}

    // 尺寸
    QSize sizeHint() const override {
        return QSize(codeEditor->lineNumberAreaWidth(), 0);
    }

protected:
    // 绘制
    void paintEvent(QPaintEvent *event) override {
        codeEditor->lineNumberAreaPaintEvent(event);
    }

private:
    CodeEditor *codeEditor;
};


#endif // CODEEDITOR_H
